﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Web.UI.WebControls;

namespace Sortable
{
    public class GridViewEx : GridView, IPageableItemContainer, ISortableItemContainer
    {
        /// <summary>
        /// Gets or sets if the grid view pager is hidden
        /// </summary>
        [Category("Paging"), DefaultValue(false), Description("Choose to hide the original pager if an external pager is used")]
        public virtual bool HidePager
        {
            get
            {
                object obj2 = this.ViewState["HidePager"];
                return obj2 != null && (bool)obj2;
            }
            set
            {
                bool hidePager = this.HidePager;
                if (value != hidePager)
                {
                    this.ViewState["HidePager"] = value;
                    if (base.Initialized) base.RequiresDataBinding = true;
                }
            }
        }

        protected override void InitializePager(GridViewRow row, int columnSpan, PagedDataSource pagedDataSource)
        {
            //If the pager is not hidden initialize it
            if (!this.HidePager) base.InitializePager(row, columnSpan, pagedDataSource);
        }

        protected virtual void OnTotalRowCountAvailable(PageEventArgs e)
        {
            EventHandler<PageEventArgs> handler = (EventHandler<PageEventArgs>)base.Events[EventTotalRowCountAvailable];
            if (handler != null) handler(this, e);
        }

        protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
        {
            int rows = base.CreateChildControls(dataSource, dataBinding);

            //  if the paging feature is enabled, determine the total number of rows in the datasource
            if (this.AllowPaging)
            {
                //  if we are databinding, use the number of rows that were created, otherwise cast the datasource to an Collection and use that as the count
                int totalRowCount = dataBinding ? rows : ((ICollection)dataSource).Count;

                //  raise the row count available event
                IPageableItemContainer pageableItemContainer = this as IPageableItemContainer;

                this.OnTotalRowCountAvailable(new PageEventArgs(pageableItemContainer.StartRowIndex, pageableItemContainer.MaximumRows, totalRowCount));
            }

            return rows;
        }

        protected override void LoadControlState(object savedState)
        {
            base.LoadControlState(savedState);
            if (!this.IsViewStateEnabled) this.OnTotalRowCountAvailable(new PageEventArgs(this.PageSize * this.PageIndex, this.PageSize, this.PageSize * this.PageCount));
        }

        //IPageableItemContainer implementation
        int IPageableItemContainer.MaximumRows
        {
            get { return this.PageSize; }
        }

        void IPageableItemContainer.SetPageProperties(int startRowIndex, int maximumRows, bool databind)
        {
            int newPageIndex = (startRowIndex / maximumRows);
            this.PageSize = maximumRows;
            if (this.PageIndex != newPageIndex)
            {
                bool isCanceled = false;
                if (databind)
                {
                    //create the event arguments and raise the event
                    GridViewPageEventArgs args = new GridViewPageEventArgs(newPageIndex);
                    this.OnPageIndexChanging(args);
                    isCanceled = args.Cancel;
                    newPageIndex = args.NewPageIndex;
                }

                //if the event wasn't cancelled change the paging values
                if (!isCanceled)
                {
                    this.PageIndex = newPageIndex;
                    if (databind) this.OnPageIndexChanged(EventArgs.Empty);
                }
                if (databind) this.RequiresDataBinding = true;
            }
        }

        int IPageableItemContainer.StartRowIndex
        {
            get { return this.PageSize * this.PageIndex; }
        }

        private static readonly object EventTotalRowCountAvailable = new object();
        event EventHandler<PageEventArgs> IPageableItemContainer.TotalRowCountAvailable
        {
            add { base.Events.AddHandler(EventTotalRowCountAvailable, value); }
            remove { base.Events.RemoveHandler(EventTotalRowCountAvailable, value); }
        }
    }
}